# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
## NPSolitaire:
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## from PySolFC code:
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
"""
Game persistance. load / dump of game details.
"""
__docformat__ = 'restructuredtext en'
_ = lambda n: n

import pickle

from ..settings import PACKAGE, VERSION
from ..gamelib.data import GAME_DB
from ..viewlib.dialog import Dialog




def load(filename=None, bookmark=None):
    """
    Load game data from filname or bookmark.

    .. load(filename:str|bookmark:int) -> dict

    *Parameters:*
      [filename | bookmark]: {string | bytes}
        Indicate what loads. *Only one keyword may be given.*

    *Variables:*
      nextgame['bookmark'] - {bytes}
        When given bookmark, load result from index.

    *Raises*:
      ExceptionError:
        When given both filename and bookmark (Only 1 maybe given.).
    """
    update_text = _('Prior {} v{} cannot be loaded. {}')

    if filename is not None and bookmark is None:
        game = pickle.load(filename)
    elif bookmark is not None and filename is None:
        game = pickle.loads(bookmark)
    else:
        raise Exception(_('only 1 keyword may be passed'))

    if not isinstance(game, dict):
        Dialog.error(text=_('Internal Error occured.'))
        game = {}
        return

    # verify program details
    pkg, ver = game['name'], game['version']
    if not isinstance(pkg, str) and not isinstance(ver, float):
        Dialog.error(text=_('Internal Error occured.'))
        return {}

    if ver < VERSION or pkg != PACKAGE:
        Dialog.error(text=_('Error loading game.'),
                     err=update_text.format(pkg, '.'.join(ver),
                                            'Program has changed.'))
        return {}

    # verify game details.  TODO transition to name instead of ID.
    gid, ver = game['game_id'], game['game_version']
    if not isinstance(gid, int) and not isinstance(ver, float):
        Dialog.error(text=_('Internal Error occured.'))
        return {}

    info = GAME_DB[GAME_DB.find(gid, 'id')]
    if info and not info['si']['version'] == ver:
        Dialog.error(text=_('Error loading game.'),
                     err=update_text.format(info['name'], ver,
                                            'Game has changed.'))
        return {}

    if not 0 <= game['update_flag'] <= 2:
        Dialog.error(text=_('Internal Error occured.'))
        return {}
    return game


def dump(game, filename=None, bookmark=None, update_stats=0):
    """
    Dump game to given filename or bookmark.

    .. dump(game:Game, filename:str|bookmark:int[, update_stats:int=0]) -> None

    *Parameters:*
      [filename | bookmark]: {text | number}
        Indicate what loads. *Only one keyword may be given.*
      update_stats: {number}
        Value given as flag to indicate how to handle stats and bookmarks.

          *0* - Do dump nextgame. Do increment save.

          *1* - Do dump nextgame. Do not increment save.

          *2* - Do not dump nextgame. Do not increment save.

    *Variables:*
      nextgame['bookmark'] - {bytes}
        When given bookmark, dump result for index.
    *Raises*:
      AssertionError:
        When given update_stats is out of range (0..2).
      ExceptionError:
        When given both filename and bookmark (Only 1 maybe given.).
    """
    assert 0 <= update_stats <= 2
    if not game.is_finish:
        game.log()
    # format

    if update_stats == 0:
        game.nextgame['counter']['save'] += 1
    nextgame = {}
    if update_stats in [0, 1]:
        nextgame = {'bookmark': game.nextgame['bookmark'],
                    'counter':  game.nextgame['counter']}

    game_dict = dict(name=PACKAGE, version=VERSION,
                     game_id=game['id'], game_version=game['si']['version'],
                     # attribute
                     seed=game.random, num_piles=len(game.allstacks),
                     piles=tuple((p.id, dict(p.cap),
                                  tuple((c._id, c.face_up,)
                                        for c in p.cards))
                                  for p in game.allstacks),
                     cur_round=game.talon.round, move=game._move,
                     status=game.status,
                     # session
                     update_flag=update_stats, nextgame=nextgame,
                     timer=game._timer)

    # # write data: file | cache
    if filename is not None and bookmark is None:
        pickle.dump(game_dict, filename)
    elif bookmark is not None and filename is None:
        assert bookmark in range(10)
        game.nextgame['bookmark'][bookmark] = pickle.dumps(game_dict)
    else:
        raise Exception(_('only 1 keyword may be passed'))